/**
 * @file   Value.cpp
 * @author Djuro Drljaca (djurodrljaca@gmail.com)
 * @date   2013-05-03
 * @brief  DataBus Value.
 *
 * Copyright (C) 2013 Djuro Drljaca <djurodrljaca@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <DataBus/Common/Value.h>

union floatConverter_t
{
    float valueFloat;
    quint32 valueUInt32;
};

union doubleConverter_t
{
    double valueDouble;
    quint64 valueUInt64;
};

DataBus::Value::Value()
    : m_value(),
      m_dataType(DataType_Invalid)
{
}

DataBus::Value::Value(const bool value)
    : m_value(),
      m_dataType(DataType_Boolean)
{
    m_value.valueBoolean = value;
}

DataBus::Value::Value(const qint8 value)
    : m_value(),
      m_dataType(DataType_Int8)
{
    m_value.valueInt8 = value;
}

DataBus::Value::Value(const quint8 value)
    : m_value(),
      m_dataType(DataType_UInt8)
{
    m_value.valueUInt8 = value;
}

DataBus::Value::Value(const qint16 value)
    : m_value(),
      m_dataType(DataType_Int16)
{
    m_value.valueInt16 = value;
}

DataBus::Value::Value(const quint16 value)
    : m_value(),
      m_dataType(DataType_UInt16)
{
    m_value.valueUInt16 = value;
}

DataBus::Value::Value(const qint32 value)
    : m_value(),
      m_dataType(DataType_Int32)
{
    m_value.valueInt32 = value;
}

DataBus::Value::Value(const quint32 value)
    : m_value(),
      m_dataType(DataType_UInt32)
{
    m_value.valueUInt32 = value;
}

DataBus::Value::Value(const qint64 value)
    : m_value(),
      m_dataType(DataType_Int64)
{
    m_value.valueInt64 = value;
}

DataBus::Value::Value(const quint64 value)
    : m_value(),
      m_dataType(DataType_UInt64)
{
    m_value.valueUInt64 = value;
}

DataBus::Value::Value(const float value)
    : m_value(),
      m_dataType(DataType_Float)
{
    m_value.valueFloat = value;
}

DataBus::Value::Value(const double value)
    : m_value(),
      m_dataType(DataType_Double)
{
    m_value.valueDouble = value;
}

DataBus::Value::Value(const QString &value)
    : m_value(),
      m_dataType(DataType_String)
{
    m_value.valueString = new QString(value);
}

DataBus::Value::Value(const QByteArray &value)
    : m_value(),
      m_dataType(DataType_ByteArray)
{
    m_value.valueByteArray = new QByteArray(value);
}

DataBus::Value::Value(const Value &copyin)
    : m_value(),
      m_dataType(DataType_Invalid)
{
    *this = copyin;
}

DataBus::Value::~Value()
{
    if (m_dataType == DataType_String)
    {
        delete m_value.valueString;
    }
    else if (m_dataType == DataType_ByteArray)
    {
        delete m_value.valueByteArray;
    }
}

DataBus::Value & DataBus::Value::operator=(const Value &rhs)
{
    switch (rhs.m_dataType)
    {
        case DataType_Boolean:
        {
            setBoolean(rhs.getBoolean());
            break;
        }

        case DataType_Int8:
        {
            setInt8(rhs.getInt8());
            break;
        }

        case DataType_UInt8:
        {
            setUInt8(rhs.getUInt8());
            break;
        }

        case DataType_Int16:
        {
            setInt16(rhs.getInt16());
            break;
        }

        case DataType_UInt16:
        {
            setUInt16(rhs.getUInt16());
            break;
        }

        case DataType_Int32:
        {
            setInt32(rhs.getInt32());
            break;
        }

        case DataType_UInt32:
        {
            setUInt32(rhs.getUInt32());
            break;
        }

        case DataType_Int64:
        {
            setInt64(rhs.getInt64());
            break;
        }

        case DataType_UInt64:
        {
            setUInt64(rhs.getUInt64());
            break;
        }

        case DataType_Float:
        {
            setFloat(rhs.getFloat());
            break;
        }

        case DataType_Double:
        {
            setDouble(rhs.getDouble());
            break;
        }

        case DataType_String:
        {
            setString(rhs.getString());
            break;
        }

        case DataType_ByteArray:
        {
            setByteArray(rhs.getByteArray());
            break;
        }

        default:
        {
            break;
        }
    }

    return *this;
}

DataBus::DataType DataBus::Value::getDataType() const
{
    return m_dataType;
}

bool DataBus::Value::getBoolean() const
{
    if (m_dataType != DataType_Boolean)
    {
        return false;
    }

    return m_value.valueBoolean;
}

void DataBus::Value::setBoolean(const bool value)
{
    if (m_dataType != DataType_Boolean)
    {
        if (m_dataType == DataType_String)
        {
            delete m_value.valueString;
        }
        else if (m_dataType == DataType_ByteArray)
        {
            delete m_value.valueByteArray;
        }

        m_dataType = DataType_Boolean;
    }

    m_value.valueBoolean = value;
}

qint8 DataBus::Value::getInt8() const
{
    if (m_dataType != DataType_Int8)
    {
        return 0;
    }

    return m_value.valueInt8;
}

void DataBus::Value::setInt8(const qint8 value)
{
    if (m_dataType != DataType_Int8)
    {
        if (m_dataType == DataType_String)
        {
            delete m_value.valueString;
        }
        else if (m_dataType == DataType_ByteArray)
        {
            delete m_value.valueByteArray;
        }

        m_dataType = DataType_Int8;
    }

    m_value.valueInt8 = value;
}

quint8 DataBus::Value::getUInt8() const
{
    if (m_dataType != DataType_UInt8)
    {
        return 0u;
    }

    return m_value.valueUInt8;
}

void DataBus::Value::setUInt8(const quint8 value)
{
    if (m_dataType != DataType_UInt8)
    {
        if (m_dataType == DataType_String)
        {
            delete m_value.valueString;
        }
        else if (m_dataType == DataType_ByteArray)
        {
            delete m_value.valueByteArray;
        }

        m_dataType = DataType_UInt8;
    }

    m_value.valueUInt8 = value;
}

qint16 DataBus::Value::getInt16() const
{
    if (m_dataType != DataType_Int16)
    {
        return 0;
    }

    return m_value.valueInt16;
}

void DataBus::Value::setInt16(const qint16 value)
{
    if (m_dataType != DataType_Int16)
    {
        if (m_dataType == DataType_String)
        {
            delete m_value.valueString;
        }
        else if (m_dataType == DataType_ByteArray)
        {
            delete m_value.valueByteArray;
        }

        m_dataType = DataType_Int16;
    }

    m_value.valueInt16 = value;
}

quint16 DataBus::Value::getUInt16() const
{
    if (m_dataType != DataType_UInt16)
    {
        return 0u;
    }

    return m_value.valueUInt16;
}

void DataBus::Value::setUInt16(const quint16 value)
{
    if (m_dataType != DataType_UInt16)
    {
        if (m_dataType == DataType_String)
        {
            delete m_value.valueString;
        }
        else if (m_dataType == DataType_ByteArray)
        {
            delete m_value.valueByteArray;
        }

        m_dataType = DataType_UInt16;
    }

    m_value.valueUInt16 = value;
}

qint32 DataBus::Value::getInt32() const
{
    if (m_dataType != DataType_Int32)
    {
        return 0;
    }

    return m_value.valueInt32;
}

void DataBus::Value::setInt32(const qint32 value)
{
    if (m_dataType != DataType_Int32)
    {
        if (m_dataType == DataType_String)
        {
            delete m_value.valueString;
        }
        else if (m_dataType == DataType_ByteArray)
        {
            delete m_value.valueByteArray;
        }

        m_dataType = DataType_Int32;
    }

    m_value.valueInt32 = value;
}

quint32 DataBus::Value::getUInt32() const
{
    if (m_dataType != DataType_UInt32)
    {
        return 0u;
    }

    return m_value.valueUInt32;
}

void DataBus::Value::setUInt32(const quint32 value)
{
    if (m_dataType != DataType_UInt32)
    {
        if (m_dataType == DataType_String)
        {
            delete m_value.valueString;
        }
        else if (m_dataType == DataType_ByteArray)
        {
            delete m_value.valueByteArray;
        }

        m_dataType = DataType_UInt32;
    }

    m_value.valueUInt32 = value;
}

qint64 DataBus::Value::getInt64() const
{
    if (m_dataType != DataType_Int64)
    {
        return 0ll;
    }

    return m_value.valueInt64;
}

void DataBus::Value::setInt64(const qint64 value)
{
    if (m_dataType != DataType_Int64)
    {
        if (m_dataType == DataType_String)
        {
            delete m_value.valueString;
        }
        else if (m_dataType == DataType_ByteArray)
        {
            delete m_value.valueByteArray;
        }

        m_dataType = DataType_Int64;
    }

    m_value.valueInt64 = value;
}

quint64 DataBus::Value::getUInt64() const
{
    if (m_dataType != DataType_UInt64)
    {
        return 0ull;
    }

    return m_value.valueUInt64;
}

void DataBus::Value::setUInt64(const quint64 value)
{
    if (m_dataType != DataType_UInt64)
    {
        if (m_dataType == DataType_String)
        {
            delete m_value.valueString;
        }
        else if (m_dataType == DataType_ByteArray)
        {
            delete m_value.valueByteArray;
        }

        m_dataType = DataType_UInt64;
    }

    m_value.valueUInt64 = value;
}

float DataBus::Value::getFloat() const
{
    if (m_dataType != DataType_Float)
    {
        return 0.0f;
    }

    return m_value.valueFloat;
}

void DataBus::Value::setFloat(const float value)
{
    if (m_dataType != DataType_Float)
    {
        if (m_dataType == DataType_String)
        {
            delete m_value.valueString;
        }
        else if (m_dataType == DataType_ByteArray)
        {
            delete m_value.valueByteArray;
        }

        m_dataType = DataType_Float;
    }

    m_value.valueFloat = value;
}

double DataBus::Value::getDouble() const
{
    if (m_dataType != DataType_Double)
    {
        return 0.0;
    }

    return m_value.valueDouble;
}

void DataBus::Value::setDouble(const double value)
{
    if (m_dataType != DataType_Double)
    {
        if (m_dataType == DataType_String)
        {
            delete m_value.valueString;
        }
        else if (m_dataType == DataType_ByteArray)
        {
            delete m_value.valueByteArray;
        }

        m_dataType = DataType_Double;
    }

    m_value.valueDouble = value;
}

QString DataBus::Value::getString() const
{
    if (m_dataType != DataType_String)
    {
        return QString();
    }

    return *(m_value.valueString);
}

void DataBus::Value::setString(const QString &value)
{
    if (m_dataType != DataType_String)
    {
        if (m_dataType == DataType_ByteArray)
        {
            delete m_value.valueByteArray;
        }

        m_value.valueString = new QString(value);
        m_dataType = DataType_String;
    }
    else
    {
        *(m_value.valueString) = value;
    }
}

QByteArray DataBus::Value::getByteArray() const
{
    if (m_dataType != DataType_ByteArray)
    {
        return QByteArray();
    }

    return *(m_value.valueByteArray);
}

void DataBus::Value::setByteArray(const QByteArray &value)
{
    if (m_dataType != DataType_ByteArray)
    {
        if (m_dataType == DataType_String)
        {
            delete m_value.valueString;
        }

        m_value.valueByteArray = new QByteArray(value);
        m_dataType = DataType_ByteArray;
    }
    else
    {
        *(m_value.valueByteArray) = value;
    }
}

bool DataBus::Value::isValid() const
{
    // Check if value is valid
    if (m_dataType == DataType_Invalid)
    {
        // Value is not valid
        return false;
    }
    else if (m_dataType == DataType_String)
    {
        if (m_value.valueString == 0)
        {
            // Value is not valid
            return false;
        }
    }
    else if (m_dataType == DataType_ByteArray)
    {
        if (m_value.valueByteArray == 0)
        {
            // Value is not valid
            return false;
        }
    }

    // Value is valid
    return true;
}

QByteArray DataBus::Value::toBinary() const
{
    // Check if value is valid
    if (isValid() == false)
    {
        return QByteArray();
    }

    // Convert data to binary based on the data type
    switch (m_dataType)
    {
        case DataType_Boolean:
        {
            return Value::toBinary(m_value.valueBoolean);
        }

        case DataType_Int8:
        {
            return Value::toBinary(m_value.valueInt8);
        }

        case DataType_UInt8:
        {
            return Value::toBinary(m_value.valueUInt8);
        }

        case DataType_Int16:
        {
            return Value::toBinary(m_value.valueInt16);
        }

        case DataType_UInt16:
        {
            return Value::toBinary(m_value.valueUInt16);
        }

        case DataType_Int32:
        {
            return Value::toBinary(m_value.valueInt32);
        }

        case DataType_UInt32:
        {
            return Value::toBinary(m_value.valueUInt32);
        }

        case DataType_Int64:
        {
            return Value::toBinary(m_value.valueInt32);
        }

        case DataType_UInt64:
        {
            return Value::toBinary(m_value.valueUInt64);
        }

        case DataType_Float:
        {
            return Value::toBinary(m_value.valueFloat);
        }

        case DataType_Double:
        {
            return Value::toBinary(m_value.valueDouble);
        }

        case DataType_String:
        {
            return Value::toBinary(*(m_value.valueString));
        }

        case DataType_ByteArray:
        {
            return Value::toBinary(*(m_value.valueByteArray));
        }

        default:
        {
            return QByteArray();
        }
    }
}

QByteArray DataBus::Value::toBinary(const bool value)
{
    if (value)
    {
        return QByteArray(1, static_cast<char>(1));
    }
    else
    {
        return QByteArray(1, static_cast<char>(0));
    }
}

QByteArray DataBus::Value::toBinary(const qint8 value)
{
    return QByteArray(1, static_cast<char>(value));
}

QByteArray DataBus::Value::toBinary(const quint8 value)
{
    return QByteArray(1, static_cast<char>(value));
}

QByteArray DataBus::Value::toBinary(const qint16 value)
{
    QByteArray data;

    data.append(static_cast<char>(value & 0xFF));
    data.append(static_cast<char>((value >> 8) & 0xFF));

    return data;
}

QByteArray DataBus::Value::toBinary(const quint16 value)
{
    QByteArray data;

    data.append(static_cast<char>(value & 0xFFu));
    data.append(static_cast<char>((value >> 8) & 0xFFu));

    return data;
}

QByteArray DataBus::Value::toBinary(const qint32 value)
{
    QByteArray data;

    data.append(static_cast<char>(value & 0xFF));
    data.append(static_cast<char>((value >> 8) & 0xFF));
    data.append(static_cast<char>((value >> 16) & 0xFF));
    data.append(static_cast<char>((value >> 24) & 0xFF));

    return data;
}

QByteArray DataBus::Value::toBinary(const quint32 value)
{
    QByteArray data;

    data.append(static_cast<char>(value & 0xFFu));
    data.append(static_cast<char>((value >> 8) & 0xFFu));
    data.append(static_cast<char>((value >> 16) & 0xFFu));
    data.append(static_cast<char>((value >> 24) & 0xFFu));

    return data;
}

QByteArray DataBus::Value::toBinary(const qint64 value)
{
    QByteArray data;

    data.append(static_cast<char>(value & 0xFFll));
    data.append(static_cast<char>((value >> 8) & 0xFFll));
    data.append(static_cast<char>((value >> 16) & 0xFFll));
    data.append(static_cast<char>((value >> 24) & 0xFFll));

    data.append(static_cast<char>((value >> 32) & 0xFFll));
    data.append(static_cast<char>((value >> 40) & 0xFFll));
    data.append(static_cast<char>((value >> 48) & 0xFFll));
    data.append(static_cast<char>((value >> 56) & 0xFFll));

    return data;
}

QByteArray DataBus::Value::toBinary(const quint64 value)
{
    QByteArray data;

    data.append(static_cast<char>(value & 0xFFull));
    data.append(static_cast<char>((value >> 8) & 0xFFull));
    data.append(static_cast<char>((value >> 16) & 0xFFull));
    data.append(static_cast<char>((value >> 24) & 0xFFull));

    data.append(static_cast<char>((value >> 32) & 0xFFull));
    data.append(static_cast<char>((value >> 40) & 0xFFull));
    data.append(static_cast<char>((value >> 48) & 0xFFull));
    data.append(static_cast<char>((value >> 56) & 0xFFull));

    return data;
}

QByteArray DataBus::Value::toBinary(const float value)
{
    QByteArray data;
    floatConverter_t converter;
    converter.valueFloat = value;

    data.append(static_cast<char>(converter.valueUInt32 & 0xFFu));
    data.append(static_cast<char>((converter.valueUInt32 >> 8) & 0xFFu));
    data.append(static_cast<char>((converter.valueUInt32 >> 16) & 0xFFu));
    data.append(static_cast<char>((converter.valueUInt32 >> 24) & 0xFFu));

    return data;
}

QByteArray DataBus::Value::toBinary(const double value)
{
    QByteArray data;
    doubleConverter_t converter;
    converter.valueDouble = value;

    data.append(static_cast<char>(converter.valueUInt64 & 0xFFull));
    data.append(static_cast<char>((converter.valueUInt64 >> 8) & 0xFFull));
    data.append(static_cast<char>((converter.valueUInt64 >> 16) & 0xFFull));
    data.append(static_cast<char>((converter.valueUInt64 >> 24) & 0xFFull));

    data.append(static_cast<char>((converter.valueUInt64 >> 32) & 0xFFull));
    data.append(static_cast<char>((converter.valueUInt64 >> 40) & 0xFFull));
    data.append(static_cast<char>((converter.valueUInt64 >> 48) & 0xFFull));
    data.append(static_cast<char>((converter.valueUInt64 >> 56) & 0xFFull));

    return data;
}

QByteArray DataBus::Value::toBinary(const QString &value)
{
    QByteArray stringData(value.toUtf8());

    if (stringData.size() > STRING_MAX_LENGTH)
    {
        stringData = stringData.left(STRING_MAX_LENGTH);
    }

    QByteArray data;

    data.append(static_cast<char>(stringData.size()));
    data.append(stringData);

    return data;
}

QByteArray DataBus::Value::toBinary(const QByteArray &value)
{
    QByteArray byteArrayData(value);

    if (byteArrayData.size() > STRING_MAX_LENGTH)
    {
        byteArrayData = byteArrayData.left(STRING_MAX_LENGTH);
    }

    QByteArray data;

    data.append(static_cast<char>(byteArrayData.size()));
    data.append(byteArrayData);

    return data;
}

bool DataBus::Value::fromBinary(const QByteArray &data, const DataType dataType, const int startIndex)
{
    // Convert data to binary based on the data type
    switch (dataType)
    {
        case DataType_Boolean:
        {
            // Convert value
            bool value = false;

            if (Value::fromBinary(data, &value, startIndex) == false)
            {
                // Error, failed to convert value
                return false;
            }

            // Save value
            setBoolean(value);
            return true;
        }

        case DataType_Int8:
        {
            // Convert value
            qint8 value = 0;

            if (Value::fromBinary(data, &value, startIndex) == false)
            {
                // Error, failed to convert value
                return false;
            }

            // Save value
            setInt8(value);
            return true;
        }

        case DataType_UInt8:
        {
            // Convert value
            quint8 value = 0;

            if (Value::fromBinary(data, &value, startIndex) == false)
            {
                // Error, failed to convert value
                return false;
            }

            // Save value
            setUInt8(value);
            return true;
        }

        case DataType_Int16:
        {
            // Convert value
            qint16 value = 0;

            if (Value::fromBinary(data, &value, startIndex) == false)
            {
                // Error, failed to convert value
                return false;
            }

            // Save value
            setInt16(value);
            return true;
        }

        case DataType_UInt16:
        {
            // Convert value
            quint16 value = 0;

            if (Value::fromBinary(data, &value, startIndex) == false)
            {
                // Error, failed to convert value
                return false;
            }

            // Save value
            setUInt16(value);
            return true;
        }

        case DataType_Int32:
        {
            // Convert value
            qint32 value = 0;

            if (Value::fromBinary(data, &value, startIndex) == false)
            {
                // Error, failed to convert value
                return false;
            }

            // Save value
            setInt32(value);
            return true;
        }

        case DataType_UInt32:
        {
            // Convert value
            quint32 value = 0;

            if (Value::fromBinary(data, &value, startIndex) == false)
            {
                // Error, failed to convert value
                return false;
            }

            // Save value
            setUInt32(value);
            return true;
        }

        case DataType_Int64:
        {
            // Convert value
            qint64 value = 0;

            if (Value::fromBinary(data, &value, startIndex) == false)
            {
                // Error, failed to convert value
                return false;
            }

            // Save value
            setInt64(value);
            return true;
        }

        case DataType_UInt64:
        {
            // Convert value
            quint64 value = 0;

            if (Value::fromBinary(data, &value, startIndex) == false)
            {
                // Error, failed to convert value
                return false;
            }

            // Save value
            setUInt64(value);
            return true;
        }

        case DataType_Float:
        {
            // Convert value
            float value = 0.0f;

            if (Value::fromBinary(data, &value, startIndex) == false)
            {
                // Error, failed to convert value
                return false;
            }

            // Save value
            setFloat(value);
            return true;
        }

        case DataType_Double:
        {
            // Convert value
            double value = 0.0;

            if (Value::fromBinary(data, &value, startIndex) == false)
            {
                // Error, failed to convert value
                return false;
            }

            // Save value
            setDouble(value);
            return true;
        }

        case DataType_String:
        {
            // Convert value
            QString value;

            if (Value::fromBinary(data, &value, startIndex) == false)
            {
                // Error, failed to convert value
                return false;
            }

            // Save value
            setString(value);
            return true;
        }

        case DataType_ByteArray:
        {
            // Convert value
            QByteArray value;

            if (Value::fromBinary(data, &value, startIndex) == false)
            {
                // Error, failed to convert value
                return false;
            }

            // Save value
            setByteArray(value);
            return true;
        }

        default:
        {
            // Error, invalid data type
            return false;
        }
    }
}

bool DataBus::Value::fromBinary(const QByteArray &data, bool *value, const int startIndex)
{
    // Check input parameters
    if ((startIndex < 0) ||
        (startIndex >= data.size()) ||
        (value == 0))
    {
        // Error, invalid input parameters
        return false;
    }

    char bin = data.at(startIndex);

    if (bin == 1)
    {
        *value = true;
    }
    else if (bin == 0)
    {
        *value = false;
    }
    else
    {
        // Error, invalid binary value
        return false;
    }

    // Success
    return true;
}

bool DataBus::Value::fromBinary(const QByteArray &data, qint8 *value, const int startIndex)
{
    // Check input parameters
    if ((startIndex < 0) ||
        (startIndex >= data.size()) ||
        (value == 0))
    {
        // Error, invalid input parameters
        return false;
    }

    *value = static_cast<qint8>(data.at(startIndex));

    // Success
    return true;
}

bool DataBus::Value::fromBinary(const QByteArray &data, quint8 *value, const int startIndex)
{
    // Check input parameters
    if ((startIndex < 0) ||
        (startIndex >= data.size()) ||
        (value == 0))
    {
        // Error, invalid input parameters
        return false;
    }

    *value = static_cast<quint8>(data.at(startIndex));

    // Success
    return true;
}

bool DataBus::Value::fromBinary(const QByteArray &data, qint16 *value, const int startIndex)
{
    // Check input parameters
    if ((startIndex < 0) ||
        ((startIndex + 2) > data.size()) ||
        (value == 0))
    {
        // Error, invalid input parameters
        return false;
    }

    quint32 val = static_cast<quint32>(data.at(startIndex)) |
                  (static_cast<quint32>(data.at(startIndex + 1)) << 8);

    *value = static_cast<qint16>(val);

    // Success
    return true;
}

bool DataBus::Value::fromBinary(const QByteArray &data, quint16 *value, const int startIndex)
{
    // Check input parameters
    if ((startIndex < 0) ||
        ((startIndex + 2) > data.size()) ||
        (value == 0))
    {
        // Error, invalid input parameters
        return false;
    }

    quint32 val = static_cast<quint32>(data.at(startIndex)) |
                  (static_cast<quint32>(data.at(startIndex + 1)) << 8);

    *value = static_cast<quint16>(val);

    // Success
    return true;
}

bool DataBus::Value::fromBinary(const QByteArray &data, qint32 *value, const int startIndex)
{
    // Check input parameters
    if ((startIndex < 0) ||
        ((startIndex + 4) > data.size()) ||
        (value == 0))
    {
        // Error, invalid input parameters
        return false;
    }

    quint32 val = static_cast<quint32>(data.at(startIndex)) |
                  (static_cast<quint32>(data.at(startIndex + 1)) << 8) |
                  (static_cast<quint32>(data.at(startIndex + 2)) << 16) |
                  (static_cast<quint32>(data.at(startIndex + 3)) << 24);

    *value = static_cast<qint32>(val);

    // Success
    return true;
}

bool DataBus::Value::fromBinary(const QByteArray &data, quint32 *value, const int startIndex)
{
    // Check input parameters
    if ((startIndex < 0) ||
        ((startIndex + 4) > data.size()) ||
        (value == 0))
    {
        // Error, invalid input parameters
        return false;
    }

    *value = static_cast<quint32>(data.at(startIndex)) |
             (static_cast<quint32>(data.at(startIndex + 1)) << 8) |
             (static_cast<quint32>(data.at(startIndex + 2)) << 16) |
             (static_cast<quint32>(data.at(startIndex + 3)) << 24);

    // Success
    return true;
}

bool DataBus::Value::fromBinary(const QByteArray &data, qint64 *value, const int startIndex)
{
    // Check input parameters
    if ((startIndex < 0) ||
        ((startIndex + 8) > data.size()) ||
        (value == 0))
    {
        // Error, invalid input parameters
        return false;
    }

    quint64 val = static_cast<quint64>(data.at(startIndex)) |
                  (static_cast<quint64>(data.at(startIndex + 1)) << 8) |
                  (static_cast<quint64>(data.at(startIndex + 2)) << 16) |
                  (static_cast<quint64>(data.at(startIndex + 3)) << 24) |
                  (static_cast<quint64>(data.at(startIndex + 4)) << 32) |
                  (static_cast<quint64>(data.at(startIndex + 5)) << 40) |
                  (static_cast<quint64>(data.at(startIndex + 6)) << 48) |
                  (static_cast<quint64>(data.at(startIndex + 7)) << 56);

    *value = static_cast<qint64>(val);

    // Success
    return true;
}

bool DataBus::Value::fromBinary(const QByteArray &data, quint64 *value, const int startIndex)
{
    // Check input parameters
    if ((startIndex < 0) ||
        ((startIndex + 8) > data.size()) ||
        (value == 0))
    {
        // Error, invalid input parameters
        return false;
    }

    *value = static_cast<quint64>(data.at(startIndex)) |
             (static_cast<quint64>(data.at(startIndex + 1)) << 8) |
             (static_cast<quint64>(data.at(startIndex + 2)) << 16) |
             (static_cast<quint64>(data.at(startIndex + 3)) << 24) |
             (static_cast<quint64>(data.at(startIndex + 4)) << 32) |
             (static_cast<quint64>(data.at(startIndex + 5)) << 40) |
             (static_cast<quint64>(data.at(startIndex + 6)) << 48) |
             (static_cast<quint64>(data.at(startIndex + 7)) << 56);

    // Success
    return true;
}

bool DataBus::Value::fromBinary(const QByteArray &data, float *value, const int startIndex)
{
    // Check input parameters
    if ((startIndex < 0) ||
        ((startIndex + 4) > data.size()) ||
        (value == 0))
    {
        // Error, invalid input parameters
        return false;
    }

    floatConverter_t converter;

    converter.valueUInt32 = static_cast<quint32>(data.at(startIndex)) |
                            (static_cast<quint32>(data.at(startIndex + 1)) << 8) |
                            (static_cast<quint32>(data.at(startIndex + 2)) << 16) |
                            (static_cast<quint32>(data.at(startIndex + 3)) << 24);

    *value = converter.valueFloat;

    // Success
    return true;
}

bool DataBus::Value::fromBinary(const QByteArray &data, double *value, const int startIndex)
{
    // Check input parameters
    if ((startIndex < 0) ||
        ((startIndex + 8) > data.size()) ||
        (value == 0))
    {
        // Error, invalid input parameters
        return false;
    }

    doubleConverter_t converter;

    converter.valueUInt64 = static_cast<quint64>(data.at(startIndex)) |
                            (static_cast<quint64>(data.at(startIndex + 1)) << 8) |
                            (static_cast<quint64>(data.at(startIndex + 2)) << 16) |
                            (static_cast<quint64>(data.at(startIndex + 3)) << 24) |
                            (static_cast<quint64>(data.at(startIndex + 4)) << 32) |
                            (static_cast<quint64>(data.at(startIndex + 5)) << 40) |
                            (static_cast<quint64>(data.at(startIndex + 6)) << 48) |
                            (static_cast<quint64>(data.at(startIndex + 7)) << 56);

    *value = converter.valueDouble;

    // Success
    return true;
}

bool DataBus::Value::fromBinary(const QByteArray &data, QString *value, const int startIndex)
{
    // Check input parameters
    if ((startIndex < 0) ||
        ((startIndex + 1) > data.size()) ||
        (value == 0))
    {
        // Error, invalid input parameters
        return false;
    }

    // Get length
    quint8 length = static_cast<quint8>(data.at(startIndex));

    if (length > STRING_MAX_LENGTH)
    {
        // Error, invalid length
        return false;
    }

    // Get string data
    if ((startIndex + 1 + length) > data.size())
    {
        // Error, data is not big enough
        return false;
    }

    *value = QString::fromUtf8(data.mid(startIndex + 1, length).constData(),
                               length);

    // Success
    return true;
}

bool DataBus::Value::fromBinary(const QByteArray &data, QByteArray *value, const int startIndex)
{
    // Check input parameters
    if ((startIndex < 0) ||
        ((startIndex + 1) > data.size()) ||
        (value == 0))
    {
        // Error, invalid input parameters
        return false;
    }

    // Get length
    quint8 length = static_cast<quint8>(data.at(startIndex));

    if (length > STRING_MAX_LENGTH)
    {
        // Error, invalid length
        return false;
    }

    // Get byte array
    if ((startIndex + 1 + length) > data.size())
    {
        // Error, data is not big enough
        return false;
    }

    *value = data.mid(startIndex + 1, length);

    // Success
    return true;
}
